package com.order.config;

import com.common.handler.ExchangeServiceHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfiguration {

    // 死信交换机
    @Bean
    public DirectExchange orderTaskDeadLetterExchange() {
        return new DirectExchange(ExchangeServiceHandler.ORDER_TASK_DEAD_LETTER_EXCHANGE);
    }
    // 死信队列 - 订单定时任务（订单从已支付变为已完成）
    @Bean
    public Queue orderPaidToCompletedDeadLetterQueue() {
        return new Queue("order-paid-to-completed-dead-letter-queue");
    }
    // 死信队列 - 订单定时任务校验订单状态
    @Bean
    public Queue orderCheckDeadLetterQueue() {
        return new Queue("order-check-dead-letter-queue");
    }
    // 死信队列绑定
    @Bean
    public Binding orderPaidToCompletedDeadLetterQueueBinding() {
        return BindingBuilder.bind(orderPaidToCompletedDeadLetterQueue())
                .to(orderTaskDeadLetterExchange())
                .with("order.paid.to.completed.tack");
    }
    @Bean
    public Binding orderCheckDeadLetterQueueBinding() {
        return BindingBuilder.bind(orderCheckDeadLetterQueue())
                .to(orderTaskDeadLetterExchange())
                .with("order.check.task");
    }

    // 订单定时任务队列（订单从已支付变为已完成）
    @Bean
    public Queue orderPaidToCompletedQueue() {
        return QueueBuilder.durable("order-paid-to-completed-queue")
                .lazy()
                .deadLetterExchange(orderTaskDeadLetterExchange().getName()) // 该队列绑定死信交换机
                .build();
    }
    // 订单定时任务校验订单状态
    @Bean
    public Queue orderCheckQueue() {
        return QueueBuilder.durable("order-check-queue")
                .lazy()
                .deadLetterExchange(orderTaskDeadLetterExchange().getName()) // 该队列绑定死信交换机
                .build();
    }
    // 订单定时交换机
    @Bean
    public DirectExchange orderTaskExchange() {
        return new DirectExchange(ExchangeServiceHandler.ORDER_TASK_EXCHANGE);
    }
    // 订单定时队列绑定
    @Bean
    public Binding orderPaidToCompletedQueueBinding() {
        return BindingBuilder.bind(orderPaidToCompletedQueue())
                .to(orderTaskExchange())
                .with("order.paid.to.completed.tack");
    }
    @Bean
    public Binding orderCheckQueueBinding() {
        return BindingBuilder.bind(orderCheckQueue())
                .to(orderTaskExchange())
                .with("order.check.task");
    }

    /**
     * 配置消息转换器
     *
     * @return
     */
    @Bean
    public MessageConverter messageConverter(ObjectMapper objectMapper) {
        return new Jackson2JsonMessageConverter(objectMapper);
    }

    /**
     * 消费者执行任务失败并且重试以后依然失败 ， 则需要使用`MessageRecoverer`接口来处理 , 内部包含三种不同的实现类
     * RejectAndDontRequeueRecoverer ： 重连次数耗尽，直接采用【reject】返回机制，拒绝该消息，并且删除 【默认实现】
     * ImmediateRequeueMessageRecoverer ： 重试耗尽后，返回【nack】。消息重新入队列 不断尝试重发
     * RepublishMessageRecovere ： 重连耗尽后，将失败消息投递到指定的交换机 ， 类似于当消息无法被当前消费者处理的时候 ，
     * 可以投入一个指定的交换机，该交换机只处理这种异常的消息，使用消费者监听这种异常交换机绑定的队列，每次监听到消息都可以告诫开发人员，达到一种人工处理的方案。
     */
    @Bean
    public MessageRecoverer RepublishMessageRecoverer(RabbitTemplate rabbitTemplate) {
        String exchangeName = ExchangeServiceHandler.ERROR_EXCHANGE; // 异常处理的交换机名称
        String RoutingKey = "order.error.message";    // 异常处理的交换机与队列绑定的RoutingKey
        return new RepublishMessageRecoverer(rabbitTemplate, exchangeName, RoutingKey);
    }


}
